added SSCLI 1.0
[windows-sources.git] / shared source / sscli20 / tools / nmake / build.cpp
blob105de54604a11d3daee01807e8bd3cdff52e9bdc
1 // ==++==
2 //
3 //
4 // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
5 //
6 // The use and distribution terms for this software are contained in the file
7 // named license.txt, which can be found in the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by the
9 // terms of this license.
10 //
11 // You must not remove this notice, or any other, from this software.
12 //
14 // ==--==
15 // BUILD.C -- build routines
17 // Purpose:
18 // Module contains routines to build targets
20 #include "precomp.h"
21 #ifdef _MSC_VER
22 #pragma hdrstop
23 #endif
25 // In order to make comparing dates easier, we cast the FILEINFO buffer to
26 // be of type BOGUS, which has one long where the two unsigneds (for date
27 // and time) are in the original buffer. That way only need a single compare.
30 // function prototypes for the module
31 // I make as many things static as possible, just to be extra cautious
34 int build(MAKEOBJECT*, UCHAR, time_t *, BOOL, char *, BATCHLIST**);
36 MAKEOBJECT * makeTempObject(char*, UCHAR);
37 void insertSort(DEPLIST **pDepList, DEPLIST *pElement);
38 BOOL nextToken(char**, char**);
39 DEPLIST * createDepList(BUILDBLOCK *pBlock, char *objectName);
40 void addBatch(BATCHLIST **pBatchList, RULELIST *pRule,
41 MAKEOBJECT *pObject, char *dollarLt);
42 int doBatchCommand (BATCHLIST *pBatch);
43 int RecLevel = 0; // Static recursion level. Changed from function
44 // parameter because of treatment of recursive makes.
45 int execBatchList(BATCHLIST *);
46 void freeBatchList(BATCHLIST **);
47 int invokeBuildEx(char *, UCHAR, time_t *, char *, BATCHLIST **);
49 // we have to check for expansion on targets -- firstTarget had to be
50 // expanded earlier to tell whether or not we were dealing w/ a rule, etc.,
51 // but targets from commandline might have macros, wildcards in them
53 int
54 processTree()
56 STRINGLIST *p;
57 char *v;
58 NMHANDLE searchHandle;
59 int status;
60 time_t dateTime;
62 for (p = makeTargets; p; p = makeTargets) {
63 if (_tcspbrk(makeTargets->text, "*?")) { // expand wildcards
64 struct _finddata_t finddata;
65 char *szFilename;
67 if ((szFilename = findFirst(makeTargets->text, &finddata, &searchHandle))) {
68 do {
69 v = prependPath(makeTargets->text, szFilename);
70 dateTime = getDateTime(&finddata);
71 status = invokeBuild(v, flags, &dateTime, NULL);
72 FREE(v);
73 if ((status < 0) && (ON(gFlags, F1_QUESTION_STATUS))) {
74 freeStringList(p); // Was not being freed
75 return(-1);
77 } while ((szFilename = findNext(&finddata, searchHandle)));
78 } else {
79 makeError(0, NO_WILDCARD_MATCH, makeTargets->text);
81 } else {
82 dateTime = 0L;
83 status = invokeBuild(makeTargets->text, flags, &dateTime, NULL);
84 if ((status < 0) && (ON(gFlags, F1_QUESTION_STATUS))) {
85 freeStringList(p); // Was not being freed
86 return(255);
89 makeTargets = p->next;
90 FREE_STRINGLIST(p);
92 return(0);
95 int
96 invokeBuild(
97 char *target,
98 UCHAR pFlags,
99 time_t *timeVal,
100 char *pFirstDep)
102 int status = 0;
103 BATCHLIST *pLocalBatchList = NULL;
104 status += invokeBuildEx(target,
105 pFlags,
106 timeVal,
107 pFirstDep,
108 &pLocalBatchList);
110 if (pLocalBatchList) {
111 status += execBatchList (pLocalBatchList);
112 freeBatchList (&pLocalBatchList);
115 return status;
120 invokeBuildEx(
121 char *target,
122 UCHAR pFlags,
123 time_t *timeVal,
124 char *pFirstDep,
125 BATCHLIST **ppBatchList)
127 MAKEOBJECT *object;
128 BOOL fInmakefile = TRUE;
129 int rc;
131 ++RecLevel;
132 if (!(object = findTarget(target))) {
133 object = makeTempObject(target, pFlags);
134 fInmakefile = FALSE;
136 rc = build(object, pFlags, timeVal, fInmakefile, pFirstDep, ppBatchList);
137 --RecLevel;
138 return(rc);
143 build(
144 MAKEOBJECT *object,
145 UCHAR parentFlags,
146 time_t *targetTime,
147 BOOL fInmakefile,
148 char *pFirstDep,
149 BATCHLIST **ppBatchList)
151 STRINGLIST *questionList,
152 *starList,
153 *temp,
154 *implComList;
155 struct _finddata_t finddata; // buffer for getting file times
156 NMHANDLE tHandle;
157 BUILDLIST *b;
158 RULELIST *rule; // pointer to rule found to build target
159 BUILDBLOCK *block,
160 *explComBlock;
161 DEPLIST *deps, *deplist;
162 char name[MAXNAME];
163 int rc, status = 0;
164 time_t targTime, // target's time in file system
165 newTargTime, // target's time after being rebuilt
166 tempTime,
167 depTime, // time of dependency just built
168 maxDepTime; // time of most recent dependency built
169 BOOL built; // flag: target built with doublecolon commands
170 time_t *blockTime; // points to dateTime of cmd. block
171 extern UCHAR okToDelete;
172 UCHAR okDel;
173 BATCHLIST *pLocalBatchList;
176 #ifdef DEBUG_ALL
177 printf("Build '%s'\n", object->name);
178 #endif
180 // The first dependent or inbuilt rule dependent is reqd for extmake syntax
181 // handling. If it has a value then it is the dependent corr to the inf rule
182 // otherwise it should be the first dependent specified
184 if (!object) {
185 *targetTime = 0L;
186 return(0);
189 if (ON(object->flags3, F3_BUILDING_THIS_ONE)) // detect cycles
190 makeError(0, CYCLE_IN_TREE, object->name);
192 if (object->ppBatch) {
193 // we need to build an object that is already placed in a batch list
194 // Go ahead and build the whole batch list
195 BATCHLIST **ppBatch = object->ppBatch;
196 status += execBatchList (*ppBatch);
197 freeBatchList(ppBatch);
198 *targetTime = object->dateTime;
199 return status;
202 if (ON(object->flags3, F3_ALREADY_BUILT)) {
203 if (ON(parentFlags, F2_DISPLAY_FILE_DATES))
204 printDate(RecLevel*2, object->name, object->dateTime);
205 *targetTime = object->dateTime;
206 if ( OFF(gFlags, F1_QUESTION_STATUS) &&
207 RecLevel == 1 &&
208 OFF(object->flags3, F3_OUT_OF_DATE) &&
209 findFirst(object->name, &finddata, &tHandle)) {
210 // Display 'up-to-date' msg for built level-1 targets
211 // that exist as files.
212 makeMessage(TARGET_UP_TO_DATE, object->name);
214 return(ON(object->flags3, F3_OUT_OF_DATE)? 1 : 0);
217 questionList = NULL;
218 starList = NULL;
219 implComList = NULL;
220 explComBlock = NULL;
221 block = NULL;
222 targTime = 0L;
223 newTargTime = 0L;
224 tempTime = 0L;
225 depTime = 0L;
226 maxDepTime = 0L;
227 blockTime = NULL;
228 pLocalBatchList = NULL;
231 SET(object->flags3, F3_BUILDING_THIS_ONE);
232 dollarStar = dollarAt = object->name;
234 // For Double Colon case we need the date of target before it's target's are
235 // built. For all other cases the date matters only if dependents are up
236 // to date. NOT TRUE: WE ALSO NEED THE TARGET'S TIME for @?
238 b = object->buildList;
239 if (b && ON(b->buildBlock->flags, F2_DOUBLECOLON)
240 && findFirst(object->name, &finddata, &tHandle)) {
241 targTime = getDateTime(&finddata);
245 for (; b; b = b->next) {
246 depTime = 0L;
247 block = b->buildBlock;
248 if (block->dateTime != 0) { // cmd. block already executed
249 targTime = __max(targTime, block->dateTime);
250 built = TRUE;
251 continue; // so set targTime and skip this block
253 blockTime = &block->dateTime;
255 deplist = deps = createDepList(block, object->name);
256 for (;deps; deps = deps->next) {
257 tempTime = deps->depTime;
258 rc = invokeBuildEx(deps->name, // build the dependent
259 block->flags,
260 &tempTime, NULL, &pLocalBatchList);
261 status += rc;
262 if (fOptionK && rc) {
263 MAKEOBJECT *obj = findTarget(deps->name);
264 assert(obj != NULL);
265 if (OFF(obj->flags3, F3_ERROR_IN_CHILD)) {
266 fSlashKStatus = FALSE;
267 makeError(0, BUILD_FAILED_SLASH_K, deps->name);
269 SET(object->flags3, F3_ERROR_IN_CHILD);
271 depTime = __max(depTime, tempTime);/*if rebuilt, change time*/
273 // If target exists then we need it's timestamp to correctly construct $?
275 if (!targTime && OFF(block->flags, F2_DOUBLECOLON) &&
276 findFirst(object->name, &finddata, &tHandle)) {
277 object->dateTime = targTime = getDateTime(&finddata);
280 // If dependent was rebuilt, add to $?. [RB]
282 if (ON(object->flags2, F2_FORCE_BUILD) ||
283 targTime < tempTime ||
284 (fRebuildOnTie && targTime == tempTime)
286 temp = makeNewStrListElement();
287 temp->text = makeString(deps->name);
288 appendItem(&questionList, temp);
291 // Always add dependent to $**. Must allocate new item because two
292 // separate lists. [RB]
294 temp = makeNewStrListElement();
295 temp->text = makeString(deps->name);
296 appendItem(&starList, temp);
299 if (pLocalBatchList) {
300 // Perform deferred batch builds and free batch list
301 status += execBatchList (pLocalBatchList);
302 freeBatchList(&pLocalBatchList);
305 // Free dependent list
307 for (deps = deplist; deps ; deps = deplist) {
308 FREE(deps->name);
309 deplist = deps->next;
310 FREE(deps);
313 // Now, all dependents are built.
315 if (ON(block->flags, F2_DOUBLECOLON)) {
317 // do doublecolon commands
319 if (block->buildCommands) {
320 dollarQuestion = questionList;
321 dollarStar = dollarAt = object->name;
322 dollarLessThan = dollarDollarAt = NULL;
323 dollarStarStar = starList;
324 if (((fOptionK && OFF(object->flags3, F3_ERROR_IN_CHILD)) ||
325 status == 0) &&
326 (targTime < depTime) ||
327 (fRebuildOnTie && (targTime == depTime)) ||
328 (targTime == 0 && depTime == 0) ||
329 (!block->dependents)
332 // do commands if necessary
334 okDel = okToDelete;
335 okToDelete = TRUE;
337 // if the first dependent is not set use the first one
338 // from the list of dependents
340 pFirstDep = pFirstDep ? pFirstDep : (dollarStarStar ?
341 dollarStarStar->text : NULL);
342 status += doCommands(object->name,
343 block->buildCommands,
344 block->buildMacros,
345 block->flags,
346 pFirstDep);
348 if (OFF(object->flags2, F2_NO_EXECUTE) &&
349 findFirst(object->name, &finddata, &tHandle))
350 newTargTime = getDateTime(&finddata);
351 else if (maxDepTime)
352 newTargTime = maxDepTime;
353 else
354 curTime(&newTargTime); // currentTime
356 // set time for this block
357 block->dateTime = newTargTime;
358 built = TRUE;
360 // If these both point to the same list,
361 // don't free twice.
363 if (starList != questionList) {
364 freeStringList(starList);
365 freeStringList(questionList);
366 } else {
367 freeStringList(starList);
370 starList = questionList = NULL;
371 okToDelete = okDel;
374 if (fOptionK && ON(object->flags3, F3_ERROR_IN_CHILD))
375 makeError(0, TARGET_ERROR_IN_CHILD, object->name);
377 } else {
379 // singlecolon; set explComBlock
381 if (block->buildCommands)
382 if (explComBlock)
383 makeError(0, TOO_MANY_RULES, object->name);
384 else
385 explComBlock = block;
386 maxDepTime = __max(maxDepTime, depTime);
389 if (ON(block->flags, F2_DOUBLECOLON) && !b->next) {
390 CLEAR(object->flags3, F3_BUILDING_THIS_ONE);
391 SET(object->flags3, F3_ALREADY_BUILT);
392 if (status > 0)
393 SET(object->flags3, F3_OUT_OF_DATE);
394 else
395 CLEAR(object->flags3, F3_OUT_OF_DATE);
396 targTime = __max(newTargTime, targTime);
397 object->dateTime = targTime;
398 *targetTime = targTime;
399 return(status);
403 dollarLessThan = dollarDollarAt = NULL;
405 if (!(targTime = *targetTime)) {
406 if (object->dateTime) {
407 targTime = object->dateTime;
408 } else if (findFirst(object->name, &finddata, &tHandle)) {
409 targTime = getDateTime(&finddata);
413 if (ON(object->flags2, F2_DISPLAY_FILE_DATES)) {
414 printDate(RecLevel*2, object->name, targTime);
417 built = FALSE;
419 // look for implicit dependents and use rules to build the target
421 // The order of the if's decides whether the dependent is inferred
422 // from the inference rule or not, even when the explicit command block is
423 // present, currently it is infered (XENIX MAKE compatibility)
425 if ((rule = useRule(object,
426 name,
427 targTime,
428 &questionList,
429 &starList,
430 &status,
431 &maxDepTime,
432 &pFirstDep))
434 if (!explComBlock) {
435 dollarLessThan = name;
436 implComList = rule->buildCommands;
440 dollarStar = dollarAt = object->name;
441 dollarQuestion = questionList;
442 dollarStarStar = starList;
444 if (((fOptionK && OFF(object->flags3, F3_ERROR_IN_CHILD)) || status == 0) &&
445 (targTime < maxDepTime ||
446 (fRebuildOnTie && (targTime == maxDepTime)) ||
447 (targTime == 0 && maxDepTime == 0) ||
448 ON(object->flags2, F2_FORCE_BUILD)
451 okDel = okToDelete; // Yes, can delete while executing commands
452 okToDelete = TRUE;
454 if (explComBlock) {
455 // if the first dependent is not set use the first one from the
456 // list of dependents
457 pFirstDep = pFirstDep ? pFirstDep :
458 (dollarStarStar ? dollarStarStar->text : NULL);
459 status += doCommands(object->name, // do singlecolon commands
460 explComBlock->buildCommands,
461 explComBlock->buildMacros,
462 explComBlock->flags,
463 pFirstDep);
465 else if (implComList) {
466 if (rule->fBatch && OFF(gFlags, F1_NO_BATCH)) {
467 addBatch(ppBatchList,
468 rule,
469 object,
470 dollarLessThan);
472 else {
473 status += doCommands(object->name, // do rule's commands
474 implComList,
475 rule->buildMacros,
476 object->flags2,
477 pFirstDep);
480 else if (ON(gFlags, F1_TOUCH_TARGETS)) { // for /t with no commands...
481 if (block)
482 status += doCommands(object->name,
483 block->buildCommands,
484 block->buildMacros,
485 block->flags,
486 pFirstDep);
488 // if Option K specified don't exit ... pass on return code
489 else if (!fInmakefile && targTime == 0) { // lose
490 // If option K, then set the return code 'status'
491 // to 1 to indicate a failure.
492 if (fOptionK) {
493 status = 1;
494 } else
495 makeError(0, CANT_MAKE_TARGET, object->name);
497 okToDelete = okDel;
498 // if cmd exec'ed or has 0 deps then currentTime else max of dep times
499 if (explComBlock || implComList || !dollarStarStar) {
500 curTime(&newTargTime);
502 // Add 2 to ensure the time for this node is >= the time the file
503 // system might have used (mainly useful when running a very fast
504 // machine where the file system doesn't have the resolution of the
505 // system timer... We don't have to to this in the curTime
506 // above since it's only hit when nothing is built anywhere...
508 newTargTime +=2;
509 } else
510 newTargTime = maxDepTime;
512 if (blockTime && explComBlock)
513 // set block's time, if a real cmd. block was executed
514 *blockTime = newTargTime;
516 else if (OFF(gFlags, F1_QUESTION_STATUS) &&
517 RecLevel == 1 &&
518 !built &&
519 OFF(object->flags3, F3_ERROR_IN_CHILD))
520 makeMessage(TARGET_UP_TO_DATE, object->name);
522 if (fOptionK && status) {
523 // We should set fSlashKStatus=FALSE so that main() knows the
524 // build failed under /K option.
525 fSlashKStatus = FALSE;
527 if (ON(object->flags3, F3_ERROR_IN_CHILD))
528 makeError(0, TARGET_ERROR_IN_CHILD, object->name);
529 else if (RecLevel == 1)
530 makeError(0, BUILD_FAILED_SLASH_K, object->name);
533 if (ON(gFlags, F1_QUESTION_STATUS) && RecLevel == 1 ) {
534 // If these both point to the same list, don't free twice.
536 if (starList!= questionList) {
537 freeStringList(starList);
538 freeStringList(questionList);
539 } else {
540 freeStringList(starList);
543 return(numCommands ? -1 : 0);
546 CLEAR(object->flags3, F3_BUILDING_THIS_ONE);
547 if (!object->ppBatch) {
548 SET(object->flags3, F3_ALREADY_BUILT);
549 if (status > 0)
550 SET(object->flags3, F3_OUT_OF_DATE);
551 else
552 CLEAR(object->flags3, F3_OUT_OF_DATE);
555 targTime = __max(newTargTime, targTime);
556 object->dateTime = targTime;
558 *targetTime = targTime;
560 // If these both point to the same list, don't free twice.
562 if (starList!= questionList) {
563 freeStringList(starList);
564 freeStringList(questionList);
565 } else {
566 freeStringList(starList);
569 return(status);
572 DEPLIST *
573 createDepList(
574 BUILDBLOCK *bBlock,
575 char *objectName
578 BOOL again; // flag: wildcards found in dependent name
579 char *s, *t;
580 char *source, *save, *token;
581 char *depName, *depPath;
582 char *tempStr;
583 STRINGLIST *sList, *pMacros;
584 DEPLIST *depList = NULL, *pNew;
585 struct _finddata_t finddata;
586 NMHANDLE searchHandle;
588 pMacros = bBlock->dependentMacros;
590 // expand Macros in Dependent list
591 for (sList = bBlock->dependents; sList; sList = sList->next) {
592 for (s = sList->text; *s && *s != '$'; s = _tcsinc(s)) {
593 if (*s == ESCH)
594 s++;
596 if (*s) {
597 // set $$@ properly, The dependency macros will then expand right
598 dollarDollarAt = objectName;
599 source = expandMacros(sList->text, &pMacros);
600 } else
601 source = sList->text;
603 save = makeString(source);
604 // build list for all dependents
605 for (t = save; nextToken(&t, &token);) {
606 if (*token == '{') {
607 // path list found
608 for (depName = token; *depName && *depName != '}'; depName = _tcsinc(depName)) {
609 if (*depName == ESCH) {
610 depName++;
614 if (*depName) {
615 *depName++ = '\0';
616 ++token;
618 } else {
619 depName = token; // If no path list, set
620 token = NULL; // token to null.
623 // depName is now name of dependency file ...
625 again = FALSE;
626 putDateTime(&finddata, 0L);
627 depPath = makeString(depName);
628 if (_tcspbrk(depName, "*?") || token) { // do wildcards in filename
629 if ((tempStr = searchPath(token, depName, &finddata, &searchHandle))){
630 again = TRUE;
631 FREE(depPath);
632 depName = tempStr; // depName gets actual name
633 depPath = prependPath(depName, getFileName(&finddata));
634 } // depPath gets full path
637 // Add to the dependent list
639 do {
640 pNew = MakeNewDepListElement();
641 // if name contains spaces and has no quotes,
642 // add enclosing quotes around it
643 if (_tcschr(depPath, ' ') && !_tcschr(depPath, '\"')) {
644 pNew->name = (char *)rallocate (_tcslen(depPath)+3);
645 *(pNew->name) = '\"';
646 *(pNew->name+1) = '\0';
647 _tcscat (pNew->name, depPath);
648 _tcscat (pNew->name, "\"");
650 else {
651 pNew->name = makeString(depPath);
654 if (!fDescRebuildOrder || findFirst(depPath, &finddata, &searchHandle)) {
655 pNew->depTime = getDateTime(&finddata);
656 } else {
657 pNew->depTime = 0L;
660 if (fDescRebuildOrder) {
661 insertSort(&depList, pNew);
662 } else {
663 appendItem((STRINGLIST**)&depList, (STRINGLIST*)pNew);
665 FREE(depPath);
666 } while (again &&
667 _tcspbrk(depName, "*?") && // do all wildcards
668 findNext(&finddata, searchHandle) &&
669 (depPath = prependPath(depName, getFileName(&finddata)))
672 // One dependent (w/wildcards?) was expanded
674 if (source != sList->text) {
675 FREE(source);
678 FREE(save);
681 // Now, all dependents are done ...
683 return(depList);
686 void
687 insertSort(
688 DEPLIST **pDepList,
689 DEPLIST *pElement
692 time_t item;
693 DEPLIST *pList, *current;
695 item = pElement->depTime;
696 pList = current = *pDepList;
698 for (;pList && item <= pList->depTime; pList = pList->next) {
699 current = pList;
702 if (current == pList) {
703 *pDepList = pElement;
704 } else {
705 current->next = pElement;
706 pElement->next = pList;
711 BOOL
712 nextToken(
713 char **pNext,
714 char **pToken
717 char *s = *pNext;
719 while (*s && WHITESPACE(*s)) {
720 ++s;
723 if (!*(*pToken = s)) {
724 return(FALSE);
727 // Token begins here
728 *pToken = s;
730 if (*s == '"') {
731 while (*s && *++s != '"')
734 if (!*s) {
735 // lexer possible internal error: missed a quote
736 makeError(0, LEXER_INTERNAL);
739 if (*++s) {
740 *s++ = '\0';
743 *pNext = s;
744 return(TRUE);
745 } else if (*s == '{') {
746 // skip to '}' outside quotes
747 for (;*s;) {
748 s++;
749 if (*s == '"') {
750 s++; // Skip the first quote
751 while (*s && *s++ != '"'); // Skip all including the last quote
753 if (*s == '}') {
754 break;
758 if (!*s) {
759 // lexer possible internal error: missed a brace
760 makeError(0, MISSING_CLOSING_BRACE);
763 if (*++s == '"') {
764 while (*s && *++s != '"')
767 if (!*s) {
768 // lexer possible internal error: missed a quote
769 makeError(0, LEXER_INTERNAL);
772 if (*++s) {
773 *s++ = '\0';
776 *pNext = s;
777 return(TRUE);
781 while (*s && !WHITESPACE(*s)) {
782 ++s;
785 if (*s) {
786 *s++ = '\0';
789 *pNext = s;
791 return(TRUE);
795 void
796 freeStringList(
797 STRINGLIST *list
800 STRINGLIST *temp;
802 while ((temp = list)) {
803 list = list->next;
804 FREE(temp->text);
805 FREE_STRINGLIST(temp);
810 // makeTempObject -- make an object to represent implied dependents
812 // We add implied dependents to the target table, but use a special struct
813 // that has no pointer to a build list -- they never get removed.
814 // time-space trade-off -- can remove them, but will take more proc time.
816 MAKEOBJECT *
817 makeTempObject(
818 char *target,
819 UCHAR flags
822 MAKEOBJECT *object;
823 unsigned i;
825 object = makeNewObject();
826 object->name = makeString(target);
827 object->flags2 = flags;
828 object->flags3 = 0;
829 object->dateTime = 0L;
830 object->buildList = NULL;
831 i = hash(target, MAXTARGET, (BOOL) TRUE);
832 prependItem((STRINGLIST**)targetTable+i, (STRINGLIST*)object);
833 return(object);
837 void
838 addBatch(
839 BATCHLIST **ppBatchList,
840 RULELIST *pRule,
841 MAKEOBJECT *pObject,
842 char *dollarLt
845 STRINGLIST *temp;
846 BATCHLIST *pBatch;
847 BATCHLIST *pBatchPrev = 0;
849 for(pBatch = *ppBatchList; pBatch; pBatch = pBatch->next) {
850 if (pBatch->pRule == pRule &&
851 pBatch->flags == pObject->flags2)
852 break;
853 pBatchPrev = pBatch;
855 if (!pBatch) {
856 pBatch = makeNewBatchListElement();
857 pBatch->pRule = pRule;
858 pBatch->flags = pObject->flags2;
859 if (pBatchPrev) {
860 pBatchPrev->next = pBatch;
862 else if(*ppBatchList) {
863 (*ppBatchList)->next = pBatch;
865 else
866 *ppBatchList = pBatch;
869 temp = makeNewStrListElement();
870 temp->text = makeString(pObject->name);
871 appendItem(&pBatch->nameList, temp);
873 temp = makeNewStrListElement();
874 temp->text = makeString(dollarLessThan);
875 appendItem(&pBatch->dollarLt, temp);
877 assert(!pObject->ppBatch);
878 pObject->ppBatch = ppBatchList;
882 int doBatchCommand (
883 BATCHLIST *pBatch
886 size_t cbStr = 0;
887 int rc;
888 char *pchBuf;
889 STRINGLIST *pStrList;
890 RULELIST *pRule = pBatch->pRule;
891 assert (pBatch->dollarLt);
892 assert (pBatch->nameList);
894 // form $<
895 for (pStrList = pBatch->dollarLt; pStrList; pStrList = pStrList->next) {
896 cbStr += _tcslen(pStrList->text) + 1;
897 // allow space for quotes if text contains spaces
898 if (_tcschr(pStrList->text, ' '))
899 cbStr += 2;
901 pchBuf = (char *)allocate(cbStr + 1);
902 *pchBuf = 0;
903 for (pStrList = pBatch->dollarLt; pStrList; pStrList = pStrList->next) {
904 BOOL fQuote;
905 // Quote only if not quoted and contains spaces [vs98:8677]
906 fQuote = pStrList->text[0] != '"' && _tcschr(pStrList->text, ' ');
907 if (fQuote)
908 _tcscat(pchBuf, "\"");
909 _tcscat(pchBuf, pStrList->text);
910 _tcscat(pchBuf, fQuote ? "\" " : " ");
912 dollarLessThan = pchBuf;
914 rc = doCommandsEx(pBatch->nameList,
915 pRule->buildCommands,
916 pRule->buildMacros,
917 pBatch->flags,
918 NULL);
920 if (rc == 0) {
921 STRINGLIST *pName;
922 MAKEOBJECT *pObject;
923 for (pName = pBatch->nameList; pName; pName = pName->next) {
924 pObject = findTarget(pName->text);
925 assert (pObject);
927 SET(pObject->flags3, F3_ALREADY_BUILT);
928 CLEAR(pObject->flags3, F3_OUT_OF_DATE);
930 pObject->ppBatch = 0;
934 FREE (pchBuf);
935 return rc;
942 execBatchList(
943 BATCHLIST *pBList
946 int status = 0;
947 if (pBList) {
948 BATCHLIST *pBatch;
949 for (pBatch = pBList; pBatch; pBatch=pBatch->next) {
950 status += doBatchCommand (pBatch);
953 return status;
957 void
958 freeBatchList(
959 BATCHLIST **ppBList
962 BATCHLIST *pBatch = *ppBList;
964 while (pBatch) {
965 BATCHLIST *pTmp;
966 free_stringlist(pBatch->nameList);
967 free_stringlist(pBatch->dollarLt);
968 pTmp = pBatch;
969 pBatch = pBatch->next;
970 FREE(pTmp);
972 *ppBList = NULL;
976 #ifdef DEBUG_ALL
977 void
978 DumpList(
979 STRINGLIST *pList
982 // STRINGLIST *p;
983 printf("* ");
984 while (pList) {
985 printf(pList->text);
986 printf(",");
987 pList = pList->next;
989 printf("\n");
991 #endif